package com.kaibes.web.response;

import java.io.IOException;
import java.sql.DataTruncation;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.io.JsonEOFException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.kaibes.core.base.util.StringUtils;

@RestControllerAdvice
public class ResponseHanlder {
    
    @Value("${kaibes.web.response.show-exception:false}")
    private boolean showException;
    @Value("${spring.servlet.multipart.max-file-size: 1MB}")
    private String maxFileSize;
    @Autowired
    private ResponseConfig responseConfig;
    
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public ResponseEntity<Object> httpMessageNotReadableException(HttpServletRequest request, HttpMessageNotReadableException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest(String.format("请求的接口(%s:%s)数据不正确！", request.getRequestURI(), request.getMethod()));
    }
    
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<Object> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest(String.format("查找不到目标文件或接口(%s:%s)", request.getRequestURI(), request.getMethod()));
    }
    
    @ExceptionHandler(value = JsonEOFException.class)
    public ResponseEntity<Object> jsonEOFException(JsonEOFException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("方法体不是合法的JSON格式数据！");
    }
    
    @ExceptionHandler(value = MismatchedInputException.class)
    public ResponseEntity<Object> mismatchedInputException(MismatchedInputException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("方法体不是受支持的JSON格式数据！");
    }
    
    @ExceptionHandler(value = JsonParseException.class)
    public ResponseEntity<Object> jsonParseException(JsonParseException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("解析数据出错，方法体可能存在语法错误！");
    }
    
    @ExceptionHandler(value = JsonMappingException.class)
    public ResponseEntity<Object> jsonMappingException(JsonMappingException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("解析数据出错，方法体可能存在语法错误！");
    }
    
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity<Object> methodArgumentNotValidException(MethodArgumentNotValidException e) {
    	if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    } 
    
    @ExceptionHandler(HttpMessageConversionException.class)
    public ResponseEntity<Object> parameterTypeException(HttpMessageConversionException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("类型转换错误");
    }
    
    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    public ResponseEntity<Object> httpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("解析数据出错，数据类型不支持！");
    } 
    
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResponseEntity<String> maxUploadSizeExceededException(HttpServletRequest request, MaxUploadSizeExceededException e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("文件太大，上传失败：最大文件限制("+maxFileSize+")");
    } 
    
    //==============
    @ExceptionHandler(value = SQLException.class)
    public ResponseEntity<String> SQLException(SQLException e) {
        if (showException) {
        	e.printStackTrace();
        }
        return ResponseFactory.badRequest("操作失败！");
    }
    
    @ExceptionHandler(value = DataTruncation.class)
    public ResponseEntity<String> dataTruncation(DataTruncation e) {
        if (showException) {
            e.printStackTrace();
        }
        return ResponseFactory.badRequest("数据截断，数据太长，数据库操作失败！");
    }
    
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public ResponseEntity<String> SQLIntegrityConstraintViolationException(HttpServletRequest request, SQLIntegrityConstraintViolationException e) {
        if (showException) {
            e.printStackTrace();
        }
        String msg = e.getMessage();
        String[] strs = msg.split("'");
        if (msg.startsWith("Duplicate")) {
            msg = "("+strs[1]+")已经存在，请更换一个";
        } else if (msg.startsWith("Column") && msg.endsWith("cannot be null")) {
            msg = "("+strs[1]+")不能为空";
        }
        return ResponseFactory.badRequest(msg);
    } 
    
    @ExceptionHandler(ServletRequestBindingException.class)
    public ResponseEntity<String> servletRequestBindingException(HttpServletRequest request, HttpServletResponse response, ServletRequestBindingException e) {
        if (showException) {
            e.printStackTrace();
        }
        if (StringUtils.startsWith(e.getMessage(), "Missing request attribute 'userId'", "Missing request attribute 'token'")) {
            if (request.getContentType() == null) {
                try {
                    response.sendError(HttpStatus.UNAUTHORIZED.value());
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return null;
            } else {
                StatusBody statusBody = responseConfig.getStatusBodyMap().get(HttpStatus.UNAUTHORIZED.value());
                return ResponseFactory.unauthorized(statusBody.getMessage(), statusBody.getRedirect());
            }
        }
        return ResponseFactory.badRequest(e.getMessage());
    }
    
}
